program CoreTest;

uses
	SysUtils, gl, glext, CoreTypes, CoreMath, CoreConsole, CoreDisplay, CoreWindow, CoreInput, CoreOpenGL,
	CoreCamera, CoreTexture, CoreMesh, CoreShader, CoreFBO, CoreVBO, CoreFont, Core2D, CoreTimer,
	{CoreScript,} CoreCollider{, CoreGUI, CoreTestGUI};

var
	cam: TCamera;
	tex_: TTexture;
	cubeTex: TTexture;
	cube: TShader;
	mesh: TStaticMesh;
	{gui: TTestGUI;
	guiWnd: TTestWindow;
	guiBtn: TTestButton;}

procedure Quit(args: String);
begin
	wnd.Close;
end;
	
procedure Init;
var
	v: TVec4;
begin
	con.Add('quit', CON_PROC, @Quit);
	
	v := Vec4(-1, 2, 2, 0);
	glLightfv(GL_LIGHT0, GL_POSITION, @v.x);
	
	cam := TCamera.Create;
	cam.pos := Vec3(0,1,5);
	
	Mat4Persp(@cam.proj, 45, wnd.clientSize.X / wnd.clientSize.Y, 0.01, 100);
	
	tex_ := tex.Add('Data/Textures/Adibas.tga');
	cubeTex := tex.Add('Data/Textures/Cube.tga', False, TEX_CUBE);
	
	cube := TShader.Create;
	cube.Load('Data/Shaders/CubeMap.txt');
	
	mesh := TStaticMesh.Create;
	mesh.Load('Data/Meshes/Sphere.mesh');
	//mesh.UseVBO;
	
	glClearColor(0.222, 0.222, 0.222, 0);
	
	{glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fboID);
	glFramebufferTexture2DEXT( GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_CUBE_MAP_POSITIVE_X+i, m_textCubeID, 0);
	glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);}
	
	{gui := TTestGUI.Create;
	guiWnd := TTestWindow(gui.root.Add(TTestWindow.Create('wnd', 'Window', Rect(100, 100, 200, 200))));
	guiBtn := TTestButton(guiWnd.Add(TTestButton.Create('btn', 'Button', Rect(80, 80, 50, 20))));}
end;

procedure Render;
var
	i: Integer;
	vert, hor: TVec3;
begin
	ogl.Clear;
	cam.Enable;
	
	//grid
	glDisable(GL_LIGHTING);
	glLineWidth(1);
	glBegin(GL_LINES);

	for i := -20 to 20 do
	begin
		if i = 0 then
		begin
			vert := Vec3(0.109, 0.507, 0.109);
			hor := Vec3(0.812, 0, 0);
		end else
		begin
			vert := Vec3(0.289, 0.289, 0.289);
			hor := Vec3(0.289, 0.289, 0.289);
		end;
		
		glColor3fv(@vert);
		glVertex3f(i * 1, 0, -20);
		glVertex3f(i * 1, 0, 20);
		glColor3fv(@hor);
		glVertex3f(-20, 0, i * 1);
		glVertex3f(20, 0, i * 1);
	end;

	glEnd;
	
	glColor3f(1,1,1);
	glEnable(GL_LIGHTING);
	glEnable(GL_LIGHT0);
	
	cube.Enable;
	cube.Uni('cubemap').SetInt(0);
	cubeTex.Enable(0);
	mesh.Render;
	cubeTex.Disable;
	cube.Disable;
	
	//solid
	{tex_.Enable;
	mesh.Render;
	mesh.RenderNorms(0.1, Vec4(0.15, 0.68, 0.68, 1));
	
	//wireframe
	glEnable(GL_POLYGON_OFFSET_FILL);
	glPolygonOffset(4.0, 500.0);
	glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
	glColor3f(1, 0.546, 0.097);
	mesh.Render;
	glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);}
	
	tex_.Disable;
	cam.Disable;
end;

procedure Render2D;
begin
	ogl.Begin2D;
	
	{glColor4f(1,1,1,1);
	glBegin(GL_QUADS);
		glMultiTexCoord2fARB(GL_TEXTURE0_ARB, 0,1); glVertex2f(0, 0);
		glMultiTexCoord2fARB(GL_TEXTURE0_ARB, 0,0); glVertex2f(0, ogl.canvas.y);
		glMultiTexCoord2fARB(GL_TEXTURE0_ARB, 1,0); glVertex2f(ogl.canvas.x, ogl.canvas.y);
		glMultiTexCoord2fARB(GL_TEXTURE0_ARB, 1,1); glVertex2f(ogl.canvas.x, 0);
	glEnd;}
	
	tim.fpsc += 1;
	con.log.font.Render('FPS: ' + IntToStr(tim.fps), 10, 5, Vec4(1, 0.546, 0.097, 1));
	
	{gui.Render;}
	con.Render;
	
	ogl.End2D;
end;

procedure Update;
var
	moveCoef: Single;
begin
	//gui.Update(tim.dt);
	
	moveCoef := tim.dt / 2;
	
	if inp.KeyDown(IK_ESCAPE) then wnd.Close;
	if inp.KeyDown(IK_A) then cam.Strafe(moveCoef * -0.0225);
	if inp.KeyDown(IK_D) then cam.Strafe(moveCoef * 0.0225);
	if inp.KeyDown(IK_W) then cam.Move(moveCoef * 0.021);
	if inp.KeyDown(IK_S) then cam.Move(moveCoef * -0.021);
	if inp.KeyPress(IK_TYLDA) then con.Show(IK_TYLDA);
	
	if inp.KeyPress(IK_MOUSE_L) then inp.SetMousing(True);
	if inp.KeyRelease(IK_MOUSE_L) then inp.SetMousing(False);
	
	if inp.mousing then
	begin
		cam.rot.x += inp.mouseDelta.y * tim.dt / 50;
		cam.rot.y += inp.mouseDelta.x * tim.dt / 50;
	end;
end;

procedure Free;
begin
	//gui.Free;
	mesh.Free;
	cam.Free;
end;

procedure Main;
begin
	con := TConsole.Create;
	con.Init('Log.htm', True);
	con.Msg('********************************************************');
	con.Msg('* Core testing                                         *');
	con.Msg('********************************************************');
	con.Add('scr.width').SetInt(800);
	con.Add('scr.height').SetInt(600);
	con.Add('scr.fullscreen', CON_BOOL).SetBool(False);
	con.Add('scr.vsync', CON_BOOL).SetBool(False);
	con.Add('gl.depth').SetInt(24);
	con.Add('gl.stencil').SetInt(0);
	con.Msg('>Выполнение файла конфигурации:');
	con.Cmd('file Config.txt');
	con.Msg('>Инициализация:');
	
	disp := TDisplay.Create;
	wnd := CoreWindow.TWindow.Create;
	inp := TInput.Create;
	ogl := TOpenGL.Create;
	g2d := TG2D.Create;
	col := TCollider.Create;
	tim := TTimerMan.Create;
	tex := TTextureMan.Create;
	sha := TShaderMan.Create;
	//scr := TScriptMan.Create;
	
	con.Msg('Инициализация дисплея...');
	
	disp.Init;
	
	if con['scr.fullscreen'].GetBool then
	begin
		if not disp.SetMode(con['scr.width'].GetInt, con['scr.height'].GetInt) then
		begin
			con['scr.fullscreen'].SetBool(False);
		end;
	end;
	
	con.Msg('Инициализация окна...');
	
	if not wnd.Init('Ёжик', con['scr.width'].GetInt, con['scr.height'].GetInt, not con['scr.fullscreen'].GetBool, False) then
	begin
		Exit;
	end;
	
	con.Msg('Инициализация OpenGL...');
	
	if not ogl.Init(con['gl.depth'].GetInt, con['gl.stencil'].GetInt) then
	begin
		Exit;
	end;
	
	con.Msg('Инициализация остальных компонентов...');
	
	inp.Init;
	con.PostInit;
	con.Msg('>Пользовательская инициализация:');
	
	Init;
	
	con.Msg('>Погружение в вечный цикл...');
	
	while wnd.PollEvents do
	begin
		Update;
		inp.Update;
		tim.Update;
		Render;
		Render2D;
		wnd.SwapBuffers;
	end;
	
	Free;
end;

procedure MainFree;
begin
	con.Msg('>Освобождение движка:');
	con.Msg('Освобождение не основных компонентов:');
	//scr.Free;
	sha.Free;
	tex.Free;
	tim.Free;
	col.Free;
	g2d.Free;
	con.Msg('Освобождение OpenGL...');
	ogl.Free;
	inp.Free;
	con.Msg('Освобождение окна...');
	wnd.Free;
	con.Msg('Освобождение дисплея...');
	disp.Free;
	con.Msg('>Остановлен.');
	con.Free;
end;

begin
	Main;
	MainFree;
end.
